﻿using System;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Coding4Fun.TweetCraft.Wow
{
    /// <summary>
    /// Provides communication with World of Warcraft AddOns through key/value pairs.
    /// </summary>
    public interface IValueChannel
    {
        // -- Output

        /// <summary>
        /// Queues a value with the specified key to be flushed into the channel.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value</param>
        void QueueValue<T>(string key, T value);

        /// <summary>
        /// Removes a value from the queued values to be sent through the channel.
        /// </summary>
        /// <param name="key">The key.</param>
        void RemoveValue(string key);

        /// <summary>
        /// Gets a value indicating whether a value has been queued with the given key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c>, if a value has been queued; <c>false</c> otherwise.</returns>
        bool IsQueued(string key);

        /// <summary>
        /// Gets the queued value with the specified key.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <returns>The queued value.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004", Justification = "The syntax 'var value = valueChannel.GetQueuedValue<int>(...)' is considered better than 'int value = (int)valueChannel.GetQueuedValue(...)'.")]
        T GetQueuedValue<T>(string key);

        /// <summary>
        /// Flushes the queued values into the channel.
        /// </summary>
        /// <param name="keepValues">A value indicating whether values should be kept in the channel.</param>
        /// <remarks>
        /// When keepValues is set to true, the values are not cleared and the <see cref="Flushed"/> event is not raised.
        /// </remarks>
        void Flush(bool keepValues);

        /// <summary>
        /// Flushes the queued values into the channel, clears queued values and raises the <see cref="Flushed"/> event.
        /// </summary>
        void Flush();

        /// <summary>
        /// Raised when the queued values are flushed.
        /// </summary>
        event EventHandler Flushed;

        // -- Input

        /// <summary>
        /// Raised when the channel is updated.
        /// </summary>
        event EventHandler ChannelUpdated;

        /// <summary>
        /// Gets a value indicating whether a value with the given key is available in the channel.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c>, if the value is available; <c>false</c> otherwise.</returns>
        bool IsAvailable(string key);

        /// <summary>
        /// Reads a value out of the channel.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <returns>The value, if a value with the key was found; <c>null</c> otherwise.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004", Justification = "The syntax 'var value = valueChannel.ReadValue<int>(...)' is considered better than 'int value = (int)valueChannel.ReadValue(...)'.")]
        T ReadValue<T>(string key);

        // -- Channel management

        /// <summary>
        /// Keeps an existing value in the channel.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        [SuppressMessage("Microsoft.Design", "CA1004", Justification = "The syntax 'valueChannel.KeepValue<int>(...)' is considered better than 'valueChannel.KeepValue(typeof(int), ...)'.")]
        void KeepValue<T>(string key);
    }
}